import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
import random

# 设置请求头，模拟浏览器访问
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}

# 爬取单页数据的函数
def crawl_page(page_num):
    try:
        print(f'开始爬取第 {page_num} 页的分红数据...')
        
        # 新浪财经分红数据列表页URL - 找到正确的历史分红列表页面
        url = f'https://vip.stock.finance.sina.com.cn/q/go.php/vInvestConsult/kind/lsfh/index.phtml?p={page_num}'
        
        print(f'正在访问: {url}')
        
        # 发送请求
        response = requests.get(url, headers=headers, timeout=10)
        print(f'响应状态码: {response.status_code}')
        
        # 检查响应状态
        if response.status_code != 200:
            print(f'URL访问失败，状态码: {response.status_code}')
            return None
        
        response.encoding = 'gbk'  # 设置编码为gbk
        
        # 保存页面内容以便调试
        with open(f'page_{page_num}_debug.html', 'w', encoding='utf-8') as f:
            f.write(response.text)
        print(f'页面内容已保存至page_{page_num}_debug.html')
        
        # 解析HTML
        soup = BeautifulSoup(response.text, 'html.parser')
        
        # 查找所有表格
        tables = soup.find_all('table')
        print(f'第 {page_num} 页找到{len(tables)}个表格')
        
        # 查找分红数据表格（通常是页面中的主要表格）
        target_table = None
        
        # 首先尝试查找id为'dataTable'的表格（新浪财经历史分红列表页面使用的表格id）
        target_table = soup.find('table', id='dataTable')
        if target_table:
            print(f'找到id为dataTable的表格')
        else:
            # 如果没有找到id为'dataTable'的表格，尝试通过内容识别
            for i, table in enumerate(tables):
                # 检查表格是否有足够的行数和列数，以及是否包含关键文本
                rows = table.find_all('tr')
                if len(rows) > 10:  # 至少10行，说明包含较多数据
                    # 检查第一行是否包含表头信息
                    first_row = rows[0]
                    # 这里使用不同的变量名避免与全局headers冲突
                    table_headers = first_row.find_all(['th', 'td'])
                    header_texts = ''.join([h.text.strip() for h in table_headers])
                    
                    # 判断是否为分红数据表格（使用页面实际的表头关键词）
                    if any(keyword in header_texts for keyword in ['代码', '名称', '上市日期', '累计股息', '年均股息']):
                        target_table = table
                        print(f'找到分红数据表格')
                        break
        
        if not target_table:
            print(f'第 {page_num} 页未找到合适的数据表格')
            return None
        
        # 打印表格的前几行内容用于调试
        rows = target_table.find_all('tr')[:3]
        for j, row in enumerate(rows):
            cells = row.find_all(['th', 'td'])
            cell_texts = [cell.text.strip() for cell in cells]
            print(f'表格行{j+1}: {cell_texts}')
        
        # 提取表头和数据
        rows = target_table.find_all('tr')
        data = []
        # 重新初始化headers变量，确保它在任何情况下都被定义
        table_headers = []
        
        # 确定表头行
        header_row_index = 0
        # 尝试从第一行提取表头
        if rows:
            first_row = rows[0]
            header_cells = first_row.find_all(['th', 'td'])
            if header_cells:
                table_headers = [cell.text.strip() for cell in header_cells]
                print(f'从第一行提取的表头: {table_headers}')
        
        # 如果提取的表头不完整或为空，使用默认表头
        if not table_headers or len(table_headers) < 3:
            table_headers = ['代码', '名称', '上市日期', '累计股息(%)', '年均股息(%)', '分红次数', '融资总额(亿)', '融资次数', '详细']
            print(f'使用默认表头: {table_headers}')
        
        # 提取数据行（从表头行之后开始）
        data_start_index = header_row_index + 1
        print(f'从第{data_start_index+1}行开始提取数据')
        
        # 提取数据
        for tr in rows[data_start_index:]:
            cells = tr.find_all(['td'])
            row_data = [cell.text.strip() for cell in cells]
            
            # 确保行数据不为空且包含股票代码等关键信息
            if row_data and len(row_data) > 2 and any(cell.strip() for cell in row_data):
                # 清理数据，移除空单元格
                cleaned_row = [cell for cell in row_data if cell.strip() or cell == '']
                
                # 如果数据列数少于表头列数，填充空值
                while len(cleaned_row) < len(table_headers):
                    cleaned_row.append('')
                # 如果数据列数多于表头列数，截断数据
                if len(cleaned_row) > len(table_headers):
                    cleaned_row = cleaned_row[:len(table_headers)]
                
                data.append(cleaned_row)
        
        print(f'提取了{len(data)}行数据')
        
        # 创建DataFrame
        if data:
            df = pd.DataFrame(data, columns=table_headers)
            print(f'成功爬取第 {page_num} 页的数据，共{len(df)}条')
            return df
        else:
            print(f'第 {page_num} 页未提取到有效数据')
            return None
        
    except Exception as e:
        print(f'爬取第 {page_num} 页时出错: {str(e)}')
        # 保存错误信息以便调试
        with open(f'error_page_{page_num}.log', 'w', encoding='utf-8') as f:
            f.write(str(e))
        return None

# 主函数，爬取多页数据
def main():
    print('开始爬取新浪财经历史分红数据...')
    
    all_data = []
    
    # 爬取第1-100页的数据（为了测试，先爬取少量页面）
    start_page = 1
    end_page = 3  # 可以修改为100来爬取所有页面
    
    for page_num in range(start_page, end_page + 1):
        # 爬取当前页面的数据
        df = crawl_page(page_num)
        
        if df is not None and not df.empty:
            all_data.append(df)
        
        # 添加随机延迟，避免被封IP
        delay = random.uniform(2, 5)  # 增加延迟时间，避免被封
        print(f'等待{delay:.2f}秒后爬取下一页...')
        time.sleep(delay)
    
    # 合并所有数据
    if all_data:
        final_df = pd.concat(all_data, ignore_index=True)
        print(f'爬取完成，共获取{len(final_df)}条数据')
        
        # 保存数据到CSV文件（不需要安装额外的Excel库）
        output_file = '新浪财经历史分红数据.csv'
        final_df.to_csv(output_file, index=False, encoding='utf-8-sig')
        print(f'数据已保存至{output_file}')
        
        return final_df
    else:
        print('未能获取任何数据')
        return None

if __name__ == '__main__':
    main()